package com.yuuko.yuukoapi.project.system.controller

import cn.dev33.satoken.secure.BCrypt
import cn.dev33.satoken.stp.StpUtil
import cn.dev33.satoken.temp.SaTempUtil
import com.yuuko.yuukoapi.common.exception.BizException
import com.yuuko.yuukoapi.common.exception.ErrorCode
import com.yuuko.yuukoapi.common.response.AjaxResult
import com.yuuko.yuukoapi.common.response.None
import kotlinx.serialization.Serializable
import com.yuuko.yuukoapi.model.system.dto.UserLoginInput
import com.yuuko.yuukoapi.repository.system.UsersRepository
import jakarta.servlet.http.HttpServletResponse
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestHeader
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController

@RestController
@RequestMapping("/auth")
class AuthsController(
    val usersRepository: UsersRepository,
) {
    @PostMapping("/login")
    fun login(
        @RequestBody input: UserLoginInput,
        response: HttpServletResponse
    ): AjaxResult<LoginResp> {
        val findUser = usersRepository.findByUsername(input.username)
        if (findUser == null || !BCrypt.checkpw(input.password, findUser.password)) {
            throw BizException(ErrorCode.LOGIN_ERROR)
        }
        StpUtil.login(findUser.id)
        val refreshToken = SaTempUtil.createToken(findUser.id, 60 * 60 * 24 * 7)
        val accessToken = StpUtil.getTokenValue()
        val result = LoginResp(accessToken)
        response.setHeader("Refresh-Token", refreshToken)
        return AjaxResult.ok(result)
    }

    @PostMapping("/logout")
    fun logout(): AjaxResult<None?> {
        StpUtil.logout()
        return AjaxResult.ok()
    }

    @PostMapping("/refresh")
    fun refreshToken(
        @RequestHeader("Refresh-Token") refreshToken: String? = "",
    ): AjaxResult<String> {
        val userId = SaTempUtil.parseToken(refreshToken)
        if (userId == null) {
            throw BizException(ErrorCode.TOKEN_INVALID)
        }
        StpUtil.login(userId)
        val accessToken = StpUtil.getTokenValue()
        return AjaxResult.ok(accessToken)
    }

    /// 暂时没有权限码需求
    @GetMapping("/codes")
    fun getAccessCodes(): AjaxResult<List<String>> {
        return AjaxResult.ok(listOf())
    }

    /// DTOs
    @Serializable
    data class LoginResp(
        val accessToken: String,
    )

}
